package client_core

import (
	"encoding/json"
	"fmt"
	"github.com/chicken-team-outside/chicken_transmission/client_core/config"
	"github.com/chicken-team-outside/chicken_transmission/client_core/util"
	"github.com/chicken-team-outside/chicken_transmission/model"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"strconv"
)

func initNetDisk(group *gin.RouterGroup) {
	group.POST("/enable", setNetDiskEnabled)
	group.GET("/login_path", getLoginPath)
	group.GET("/config", getNetDiskConfig)
	group.POST("/config", setNetDiskDriver)
	group.POST("/check_login", checkLogin)
	group.POST("/cache_dir", setNetDiskCacheDir)
}

func tryLoadAndSetNetDiskToSfsClient() error {
	info := config.NetDiskDriverInfo()
	driver, err := util.CreateNetDiskDriver(info)
	if err == nil {
		sfsClient.SetNetDisk(driver)
		sfsClient.SetNetDiskCacheDir(config.NetDiskCacheDir())
	} else {
		return err
	}
	return nil
}

func SetNetDiskInfo(info *config.DriverInfo) error {
	dr, err := util.CreateNetDiskDriver(info)
	if err != nil {
		return fmt.Errorf("failed to create net disk driver: %w", err)
	}
	err = config.SaveNetDiskDriver(info)
	if err != nil {
		return fmt.Errorf("failed to save net disk driver: %w", err)
	}
	if config.NetDiskEnabled() {
		sfsClient.SetNetDisk(dr)
	}
	return nil
}

func setNetDiskDriver(ctx *gin.Context) {
	info := &config.DriverInfo{}
	err := ctx.BindJSON(info)
	if err != nil {
		zap.L().Warn("failed to bind json", zap.Error(err))
		BadRequest(ctx, "参数错误")
		return
	}
	err = SetNetDiskInfo(info)
	if err != nil {
		BadRequest(ctx, "保存网盘信息失败")
		return
	} else {
		Success(ctx, nil, "保存成功")
	}
}

func SetNetDiskEnabled(enabled bool) error {
	if enabled {
		err := tryLoadAndSetNetDiskToSfsClient()
		if err != nil {
			return fmt.Errorf("failed to enable net disk driver: %w", err)
		}
	} else {
		sfsClient.SetNetDisk(nil)
	}
	err := config.SaveNetDiskEnabled(enabled)
	if err != nil {
		return fmt.Errorf("failed to save net disk enabled: %w", err)
	}
	return nil
}

func SetNetDiskCacheDir(dir string) error {
	err := config.SaveNetDiskCacheDir(dir)
	if err != nil {
		return fmt.Errorf("failed to save net disk cache dir: %w", err)
	} else {
		sfsClient.SetNetDiskCacheDir(dir)
	}
	return nil
}

func setNetDiskCacheDir(ctx *gin.Context) {
	var cacheDir string
	err := ctx.BindJSON(&cacheDir)
	if err != nil {
		zap.L().Warn("failed to bind json", zap.Error(err))
		BadRequest(ctx, "参数错误")
		return
	}
	err = SetNetDiskCacheDir(cacheDir)
	if err != nil {
		zap.L().Error("failed to set net disk cache dir", zap.Error(err))
		BadRequest(ctx, "保存失败")
	} else {
		Success(ctx, nil, "保存成功")
	}
}

func setNetDiskEnabled(ctx *gin.Context) {
	var enabled bool
	err := ctx.BindJSON(&enabled)
	if err != nil {
		BadRequest(ctx, "参数错误")
		return
	}
	err = SetNetDiskEnabled(enabled)
	if err != nil {
		zap.L().Error("set net disk enabled failed", zap.Error(err))
		BadRequest(ctx, "应用失败")
	} else {
		Success(ctx, nil, "应用成功")
	}
}

func getLoginPath(ctx *gin.Context) {
	vendor, err := strconv.Atoi(ctx.Query("vendor"))
	if err != nil {
		zap.L().Warn("failed to parse vendor", zap.Error(err))
		BadRequest(ctx, "参数错误")
		return
	}
	data, err := util.CreateLoginData(ctx, model.Vendor(vendor))
	if err != nil {
		zap.L().Error("failed to create login url", zap.Error(err))
		BadRequest(ctx, "无法创建登录链接")
	} else if data == nil {
		BadRequest(ctx, fmt.Sprintf("不持的vendor: %d", vendor))
	} else {
		Success(ctx, data, "创建成功")
	}
}

type NetDiskStatus struct {
	Ok       bool         `json:"ok"`
	Vendor   model.Vendor `json:"vendor"`
	Username string       `json:"username"`
	Used     int64        `json:"used"`
	Total    int64        `json:"total"`
	Enabled  bool         `json:"enabled"`
	CacheDir string       `json:"cache_dir"`
}

func getNetDiskConfig(ctx *gin.Context) {
	info := config.NetDiskDriverInfo()
	dr := sfsClient.GetNetDisk()
	var err error
	if dr == nil {
		dr, err = util.CreateNetDiskDriver(info)
	}
	status := &NetDiskStatus{
		Vendor:   info.Vendor,
		Enabled:  config.NetDiskEnabled(),
		CacheDir: config.NetDiskCacheDir(),
	}
	if dr != nil {
		status.Ok = true
		status.Used, status.Total, err = dr.GetQuota(ctx)
		if err != nil {
			zap.L().Error("failed to get quota", zap.Error(err))
			status.Ok = false
		}
		status.Username, err = dr.UserName(ctx)
		if err != nil {
			zap.L().Error("failed to get username", zap.Error(err))
			status.Ok = false
		}
	}
	Success(ctx, status, "获取成功")
}

type CheckLoginQuery struct {
	Vendor model.Vendor    `json:"vendor"`
	Data   json.RawMessage `json:"data"`
}

func checkLogin(ctx *gin.Context) {
	query := &CheckLoginQuery{}
	err := ctx.BindJSON(query)
	if err != nil {
		zap.L().Error("failed to check login query", zap.Error(err))
		BadRequest(ctx, "参数错误")
		return
	}
	login, data, err := util.CheckNetDiskLogin(ctx, query.Vendor, query.Data)
	if data != nil {
		Success(ctx, gin.H{
			"ok":   2,
			"data": data,
		}, "验证码失效")
	} else if login != nil {
		Success(ctx, gin.H{
			"ok": 1,
			"data": &config.DriverInfo{
				Vendor:         query.Vendor,
				ConnectionInfo: login,
			},
		}, "登录成功")
	} else if err != nil {
		zap.L().Error("failed to check login", zap.Error(err))
		BadRequest(ctx, "检查登录状态失败！")
	} else {
		Success(ctx, gin.H{
			"code": 0,
		}, "等待登录")
	}
}
